package system.student.Interceptor;

import org.apache.ibatis.session.SqlSession;
import system.student.Context.LogContext;
import system.student.annotate.LogRecord;
import system.student.entity.logInfo.SystemLog;
import system.student.entity.user.UserInfo;
import system.student.mapper.SystemLogMapper;
import system.student.util.MapperUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

public class LogInterceptor implements InvocationHandler {
    private final Object target;       // 原始业务对象
    private final SystemLogMapper logMapper ;  // 日志 Mapper

    // 构造方法：传入原始对象和日志 Mapper
    public LogInterceptor(Object target, SystemLogMapper logMapper) {
        this.target = target;
        this.logMapper = logMapper;
    }

    /**
     * 动态代理核心方法：拦截方法调用
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        System.out.println("拦截的方法声明类: " + method.getDeclaringClass().getName()); // 应输出 "system.student.login.LoginStrategy"
//        System.out.println("拦截的方法名: " + method.getName()); // 应输出 "login"
//        System.out.println("方法参数类型: " + Arrays.toString(method.getParameterTypes())); // 应输出 "[class system.student.entity.login.LoginRequest]"
//        System.out.println("方法上的注解: " + Arrays.toString(method.getAnnotations())); // 应包含 @LogRecord
        // 1. 执行原始方法（业务逻辑）
        Object result = method.invoke(target, args);

// 调试：打印接口方法信息
//        System.out.println("拦截的接口方法：" + method.getDeclaringClass().getSimpleName() + "." + method.getName());

// 直接获取接口方法上的注解（优先）
        LogRecord logAnnotation = method.getAnnotation(LogRecord.class);
        // 若接口方法无注解，再查找实现类方法
        if (logAnnotation == null) {
            Method targetMethod = findTargetMethod(method, target.getClass());
            logAnnotation = targetMethod != null ? targetMethod.getAnnotation(LogRecord.class) : null;
        }

        if (logAnnotation != null) {
            // 3. 记录日志（方法执行后）
            insertLog(logAnnotation, method, args);
        }
        return result;
    }


    /**
     * 查找目标类中与代理方法同名同参数的方法（处理重写场景）
     */
    private Method findTargetMethod(Method proxyMethod, Class<?> targetClass) {
        // 打印目标类的所有方法（调试用）
        System.out.println("目标类: " + targetClass.getSimpleName());
        for (Method m : targetClass.getDeclaredMethods()) {
            System.out.printf("方法: %s(%s)%n",
                    m.getName(), Arrays.toString(m.getParameterTypes()));
        }

        try {
            return targetClass.getDeclaredMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
        } catch (NoSuchMethodException e) {
            Class<?> superClass = targetClass.getSuperclass();
            if (superClass != null && superClass != Object.class) {
                return findTargetMethod(proxyMethod, superClass);
            }
            return null;
        }
    }

    private Method findMethodInSuperClass(Method proxyMethod, Class<?> superClass) {
        if (superClass == null) return null;
        try {
            return superClass.getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return findMethodInSuperClass(proxyMethod, superClass.getSuperclass());
        }
    }


    /**
     * 插入日志到数据库
     */
    private void insertLog(LogRecord annotation, Method method, Object[] args) {
        SystemLog log = new SystemLog();
        log.setLogTime(LocalDateTime.now());       // 日志时间（当前时间）
        log.setLogLevel("INFO");                   // 日志级别（成功为 INFO）
        log.setOperation(generateOperationDesc(method, args, annotation.operation())); // 操作描述
        log.setOperatorType(annotation.operatorType()); // 操作人类型（来自注解）
        log.setOperatorId(LogContext.getCurrentUserId()); // 当前用户 ID（来自上下文）
        log.setOperatorName(LogContext.getCurrentUserName()); // 当前用户姓名（来自上下文）

        // 插入日志（使用 MyBatis Mapper）
        try (SqlSession sqlSession = MapperUtil.getSqlSessionFactory().openSession()) {
            logMapper.insertLog(log); // 插入日志
            sqlSession.commit(); // 手动提交（若 SqlSession 未自动提交）
        } catch (Exception e) {
            System.err.println("日志插入失败：" + e.getMessage()); // 记录异常，不影响主业务
        }
    }

    /**
     * 生成操作描述（优先使用注解的 operation，否则自动生成）
     */
    private String generateOperationDesc(Method method, Object[] args, String defaultOperation) {
        if (!defaultOperation.isEmpty()) {
            return defaultOperation;
        }
        // 自动生成描述（示例：方法名 + 参数）
        return method.getName() + "（参数：" + argsToString(args) + "）";
    }

    /**
     * 参数转字符串（敏感信息脱敏）
     */
    private String argsToString(Object[] args) {
        if (args == null || args.length == 0) return "";
        StringBuilder sb = new StringBuilder();
        for (Object arg : args) {
            if (arg instanceof UserInfo) { // 敏感对象脱敏（假设 UserInfo 是用户信息类）
                UserInfo user = (UserInfo) arg;
                sb.append("UserInfo{id=").append(user.getId())
                  .append(", name=").append(user.getUsername().replaceAll("(?<=\\w{2}).*(?=\\w{2})", "***"))
                  .append("}");
            } else {
                sb.append(arg);
            }
        }
        return sb.toString();
    }
}